package com.mx.adapt.pager

import android.content.Context
import android.os.Handler
import android.os.Looper
import android.util.AttributeSet
import android.view.MotionEvent
import android.widget.FrameLayout
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.mx.adapt.R
import com.mx.adapt.pager.indicator.IMXIndicatorBuild
import com.mx.adapt.pager.indicator.MXRoundIndicator
import com.mx.adapt.pager.transformer.MXEmptyTransForm
import com.mx.adapt.utils.MXUtils
import kotlin.math.roundToInt

class MXBannerView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null
) : FrameLayout(context, attrs) {
    companion object {
        const val INT_MAX_MIDDLE = (Int.MAX_VALUE / 3)
    }

    private var ratio_width: Float = 0f
    private var ratio_height: Float = 0f

    private val mHandler = Handler(Looper.getMainLooper())
    private val mxPagerView: ViewPager2 by lazy { ViewPager2(context) }

    private var showIndicator: Boolean = false
    private var indicatorBuild: IMXIndicatorBuild = MXRoundIndicator(2f)
    private var pagerAdapt: MXBannerAdapt<*>? = null
    private var onPageSelectCall: ((Int) -> Unit)? = null
    private var autoSwitchDiff = 5 * 1000L
    private var isAutoSwitch = false
    private var currentPagerIndex = -1

    init {
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.MXBannerView)
        //根据属性名称获取对应的值，属性名称的格式为类名_属性名
        try {
            ratio_width = typedArray.getFloat(R.styleable.MXBannerView_banner_ratio_width, 0.0f)
            ratio_height = typedArray.getFloat(R.styleable.MXBannerView_banner_ratio_height, 0.0f)
        } catch (e: Exception) {
        }
        typedArray.recycle()

        removeAllViews()
        addView(mxPagerView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
        isSoundEffectsEnabled = false
    }

    /**
     * 设置View的宽高比
     */
    fun setViewRatio(width: Float, height: Float) {
        ratio_width = width
        ratio_height = height
        requestLayout()
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        if (ratio_width > 0f && ratio_height > 0f) {
            //获取宽度的模式和尺寸
            val widthSize = MeasureSpec.getSize(widthMeasureSpec)
            val heightSize = ((widthSize * ratio_height) / ratio_width).roundToInt()//根据宽度和比例计算高度
            val heightMeasureSpec1 = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY)
            super.onMeasure(widthMeasureSpec, heightMeasureSpec1)
        } else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        }
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        mxPagerView.registerOnPageChangeCallback(pageCallback)
    }

    override fun onDetachedFromWindow() {
        mxPagerView.unregisterOnPageChangeCallback(pageCallback)
        super.onDetachedFromWindow()
    }

    private val pageCallback = object : ViewPager2.OnPageChangeCallback() {
        override fun onPageSelected(position: Int) {
            if (currentPagerIndex == position) return
            val size = pagerAdapt?.list?.size ?: return
            if (size <= 0) return
            currentPagerIndex = position
            val realIndex = position % size
            dispatchCurrentSelectChange(realIndex)
        }
    }

    /**
     * 设置适配器
     */
    fun setAdapt(adapt: MXBannerAdapt<*>) {
        pagerAdapt?.unregisterAdapterDataObserver(adaptChangeObserver)
        pagerAdapt?.setOnLoopChangeListener(null)

        pagerAdapt = adapt
        mxPagerView.adapter = adapt
        adapt.registerAdapterDataObserver(adaptChangeObserver)
        adapt.setOnLoopChangeListener(onLoopChangeListener)
        dispatchItemSizeChange()
    }

    fun setPageTransformer(transForm: ViewPager2.PageTransformer?) {
        mxPagerView.setPageTransformer(transForm ?: MXEmptyTransForm())
    }

    fun setIndicatorShow(show: Boolean) {
        showIndicator = show
        if (!show) {
            indicatorBuild.detachGroup(this@MXBannerView)
            (0..childCount).mapNotNull { getChildAt(it) }.forEach { view ->
                if (view != mxPagerView) {
                    removeView(view)
                }
            }
        } else {
            dispatchItemSizeChange()
        }
    }

    /**
     * 设置指示器
     */
    fun setIndicator(build: IMXIndicatorBuild) {
        indicatorBuild.detachGroup(this@MXBannerView)
        indicatorBuild = build
    }

    /**
     * 切换监听
     */
    fun setOnPageSelect(call: ((index: Int) -> Unit)) {
        onPageSelectCall = call
        call.invoke(selectIndex)
    }

    /**
     * 滚动到位置
     * @param index 目标位置
     * @param smoothScroll 是否滚动动画
     */
    fun scrollToIndex(index: Int, smoothScroll: Boolean = false) {
        val adapt = pagerAdapt ?: return
        val size = adapt.list.size
        if (size <= 0) return
        val index = index % size
        if (index >= size || index < 0) return
        if (selectIndex == index) return
        mxPagerView.unregisterOnPageChangeCallback(pageCallback)

        val realIndex = if (adapt.isLoopMode()) {
            val start = INT_MAX_MIDDLE - (INT_MAX_MIDDLE % size)
            val current = start + selectIndex
            mxPagerView.setCurrentItem(current, false)
            start + index
        } else {
            index
        }
        MXUtils.log("scrollToIndex  -->  $index")

        currentPagerIndex = realIndex
        mxPagerView.setCurrentItem(realIndex, smoothScroll)
        mxPagerView.registerOnPageChangeCallback(pageCallback)
        dispatchCurrentSelectChange(index)

        if (isAutoSwitch) {
            startAutoScroll()
        }
    }

    /**
     * 当Adapt的数据量变化时，触发修改
     */
    private var itemSize = -1
    private var isLoopMode: Boolean? = null
    private fun dispatchItemSizeChange() {
        val showIndicator = showIndicator
        val adapt = pagerAdapt ?: return
        val loop = adapt.isLoopMode()
        val size = adapt.list.size
        if (showIndicator) {
            indicatorBuild.attachGroup(this@MXBannerView)
            indicatorBuild.buildItemSize(size)
        }
        if (size > 0) {
            if (itemSize < 0 || itemSize != size || isLoopMode != loop) {
                val start = if (adapt.isLoopMode()) {
                    INT_MAX_MIDDLE - (INT_MAX_MIDDLE % size)
                } else 0
                setPagerViewCurrentItem(start, false)
                if (showIndicator) {
                    indicatorBuild.selectIndicator(size, start)
                }
                dispatchCurrentSelectChange(0)
            } else {
                dispatchCurrentSelectChange(selectIndex)
                if (showIndicator) {
                    indicatorBuild.selectIndicator(size, selectIndex)
                }
            }
        }
        itemSize = size
        isLoopMode = loop
    }

    /**
     * 当当前选中Index变化时触发这个
     */
    private var selectIndex = -1
    private fun dispatchCurrentSelectChange(index: Int) {
        val size = pagerAdapt?.list?.size ?: return
        val index = index % size
        if (selectIndex == index) return
        selectIndex = index
        onPageSelectCall?.invoke(index)
        indicatorBuild.selectIndicator(size, index)
        MXUtils.log("onPageSelected($size , $index)")
    }

    /**
     * 开始自动滚动
     */
    fun startAutoScroll(diff: Long? = null) {
        if (diff != null) {
            autoSwitchDiff = diff
        }
        isAutoSwitch = true
        mHandler.removeCallbacksAndMessages(null)
        mHandler.postDelayed(autoSwitchRun, autoSwitchDiff)

        dispatchItemSizeChange()
    }

    /**
     * 停止滚动
     */
    fun stopAutoScroll() {
        isAutoSwitch = false
        mHandler.removeCallbacksAndMessages(null)
    }

    private val onLoopChangeListener = object : MXBannerAdapt.ILoopChange {
        override fun onChange(loopMode: Boolean) {
            dispatchItemSizeChange()
        }
    }

    private val adaptChangeObserver = object : RecyclerView.AdapterDataObserver() {
        override fun onChanged() {
            dispatchItemSizeChange()
        }

        override fun onItemRangeChanged(positionStart: Int, itemCount: Int, payload: Any?) {
            dispatchItemSizeChange()
        }

        override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) {
            dispatchItemSizeChange()
        }

        override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
            dispatchItemSizeChange()
        }

        override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
            dispatchItemSizeChange()
        }

        override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
            dispatchItemSizeChange()
        }
    }

    private val autoSwitchRun = object : Runnable {
        override fun run() {
            if (!isAutoSwitch) return
            try {
                val adapt = pagerAdapt
                if (adapt != null) {
                    val size = adapt.list.size
                    val index = if (adapt.isLoopMode()) {
                        currentPagerIndex + 1
                    } else {
                        if (size > 0) ((selectIndex + 1) % size) else 0
                    }

                    currentPagerIndex = index
                    setPagerViewCurrentItem(index, true)
                    dispatchCurrentSelectChange(index)
                }
            } catch (e: Exception) {
            } finally {
                mHandler.postDelayed(this, autoSwitchDiff)
            }
        }
    }

    private fun setPagerViewCurrentItem(index: Int, smoothScroll: Boolean) {
        MXUtils.log("setCurrentItem $index $smoothScroll")
        mxPagerView.unregisterOnPageChangeCallback(pageCallback)
        mxPagerView.setCurrentItem(index, smoothScroll)
        mxPagerView.registerOnPageChangeCallback(pageCallback)
    }

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        if (isAutoSwitch) {
            if (ev.action == MotionEvent.ACTION_DOWN) {
                mHandler.removeCallbacksAndMessages(null)
            }
            if (ev.action in arrayOf(
                    MotionEvent.ACTION_UP,
                    MotionEvent.ACTION_CANCEL,
                    MotionEvent.ACTION_OUTSIDE
                )
            ) {
                mHandler.removeCallbacksAndMessages(null)
                mHandler.postDelayed(autoSwitchRun, autoSwitchDiff)
            }
        }
        return super.dispatchTouchEvent(ev)
    }
}